<template>
  <div style="width: 100%;">
    <el-select ref="selectRef" clearable :size="size" v-model="returnDataKeys" :multiple="multiple"
      :collapse-tags="collapseTags" @click.native="selectClick" @remove-tag="removeTag" @clear="clean"
      class="tree-select" v-click-outside="onClickOutside">
      <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"></el-option>
    </el-select>

    <el-popover ref="popoverRef" placement="bottom-start" trigger="click" virtual-triggering :virtual-ref="selectRef"
      :width="popoverWidth" @hide="popoverHide">

      <el-input style="margin-bottom: 5px;" placeholder="输入关键字查询" clearable v-model="filterText" v-if="showSearch">
      </el-input>
      <div style="height: 300px;">
        <el-scrollbar>
          <el-tree class="common-tree" width="100%" ref="treeRef" :data="treeData" :props="treeProps"
            :show-checkbox="multiple" :node-key="treeProps.id" :check-strictly="checkStrictly"
            :expand-on-click-node="multiple && expandClickNode" :check-on-click-node="checkClickNode"
            :highlight-current="true" :filter-node-method="filterNode" @check-change="nodeClick"
            @node-click="nodeClick">
          </el-tree>
        </el-scrollbar>
      </div>
    </el-popover>
  </div>
</template>

<script lang="ts">
export default { name: 'AutumnTreeSelect' }
</script>

<script setup lang="ts">
import { ref, unref, computed, watch, nextTick, PropType } from 'vue'
import { ClickOutside as vClickOutside } from 'element-plus'
import { $convertTree } from 'src/hooks/useCommon'
import { type TreeProp } from './type'

const props = defineProps({
  // 默认选中的节点key
  defaultKey: {
    type: [Number, String, Array],
    default() {
      return ''
    }
  },
  // 树结构数据
  data: {
    type: Array,
    default() {
      return []
    }
  },
  treeProps: {
    type: Object as PropType<TreeProp>,
    required: false,
    default: () => {
      return {
        id: 'id', // ID
        pid: 'parentId', // 父id
        label: 'name', // 显示名称
        children: 'children' // 子级字段名
      }
    }
  },
  // 配置是否可多选
  multiple: {
    type: Boolean,
    default() {
      return false
    }
  },
  // 配置多选时是否将选中值按文字的形式展示
  collapseTags: {
    type: Boolean,
    default() {
      return false
    }
  },
  // 显示复选框情况下，是否严格遵循父子不互相关联
  checkStrictly: {
    type: Boolean,
    default() {
      return false
    }
  },
  // 多选是设置点击节点是否可以选中
  checkClickNode: {
    type: Boolean,
    default() {
      return false
    }
  },
  // 多选时：点击节点展开还是点三角标
  expandClickNode: {
    type: Boolean,
    default() {
      return false
    }
  },
  size: {
    type: String,
    default() {
      return 'default'
    }
  },
  showSearch: {
    type: Boolean,
    default() {
      return true
    }
  }
})

function init() {
  if (props.defaultKey && props.defaultKey > 0) {
    if (props.multiple) {
      // 多选
      if (props.defaultKey instanceof Array) {
        const temp = props.defaultKey as Array<any>
        if (temp[0].indexOf('Object') !== -1) {
          // 对象
          setDatas(props.defaultKey);
        } else if (Object.prototype.toString.call(props.defaultKey[0]).indexOf('Number') !== -1 ||
          Object.prototype.toString.call(props.defaultKey[0]).indexOf('String') !== -1) {
          setKeys(props.defaultKey);
        }
      }
    } else {
      // 单选
      if (
        Object.prototype.toString.call(props.defaultKey).indexOf('Number') !== -1 ||
        Object.prototype.toString.call(props.defaultKey).indexOf('String') !== -1
      ) {
        setKey(props.defaultKey)
      }
    }
  }
}

// 下拉框select点击
const selectRef = ref()
const popoverRef = ref()
const onClickOutside = () => {
  unref(popoverRef).popperRef?.delayHide?.()
}
const popoverWidth = ref<string>('0px') // 弹出框框大小

const options = ref<Array<any>>([]) // select option选项
const returnDatas = ref<Array<any>>([]) // 返回给父组件数组对象
const returnDataKeys = ref<Array<any>>([]) // 返回父组件数组主键值
function selectClick() {
  selectRef.value.blur()
  nextTick(function () {
    // 设置下拉框自适应宽度
    popoverWidth.value = (selectRef.value.$el.offsetWidth - 25) + 'px'
  })
}

// 树形结构
const treeRef = ref()
const treeData = computed(() => { return JSON.stringify(props.data).indexOf(props.treeProps.children) !== -1 ? props.data : $convertTree(props.data) })
watch(() => props.data, (newVal) => nextTick(() => {
  init()
}))

// 过滤
const filterText = ref<string>('')
watch(filterText, (newVal) => treeRef.value.filter(newVal))

// 单选: 树点击方法
function nodeClick(data: any, node: any) {
  if (!props.multiple) { // 单选
    setKey(node.key)
  } else { // 多选
    const checkedKeys = treeRef.value.getCheckedKeys() // 所有被选中的节点的 key 所组成的数组数据
    const t: Array<any> = []
    options.value = checkedKeys.forEach((item: any) => {
      // 设置option选项
      const node = treeRef.value.getNode(item) // 所有被选中的节点对应的node
      t.push(node.data)
      return { label: node.label, value: node.key }
    })
    returnDataKeys.value = options.value.map((item) => item.value)
    returnDatas.value = t
  }
}

// 单选:清空选中
function clean() {
  treeRef.value.setCurrentKey(null) // 清除树选中key
  returnDatas.value = []
  returnDataKeys.value = []
  popoverHide()
}

// 单选:设置、初始化值 key
function setKey(key: any) {
  treeRef.value.setCurrentKey(key)
  const node = treeRef.value.getNode(key)
  setData(node.data)
}

// 单选：设置、初始化对象
function setData(data: any) {
  options.value = []
  options.value.push({
    label: data[props.treeProps.label],
    value: data[props.treeProps.id]
  })
  returnDatas.value = data
  returnDataKeys.value = data[props.treeProps.id]
}

// 多选:设置、初始化值 keys
function setKeys(keys: Array<any>) {
  treeRef.value.setCheckedKeys(keys)
  returnDataKeys.value = keys
  const t: Array<any> = []
  // 设置option选项
  keys.forEach((item) => {
    const node = treeRef.value.getNode(item) // 所有被选中的节点对应的node
    t.push(node.data)
  })
  returnDatas.value = t
  popoverHide()
}

// 多选:设置、初始化对象
function setDatas(data: Array<any>) {
  treeRef.value.setCheckedNodes(data)
  returnDatas.value = data
  const t: Array<any> = []

  // 设置option选项
  data.forEach((item) => {
    t.push(item[props.treeProps.id])
  })

  returnDataKeys.value = t
  popoverHide()
}

// 多选,删除任一select选项的回调
function removeTag(val: any) {
  treeRef.value.setChecked(val, false) // 设置为未选中
  const node = treeRef.value.getNode(val) // 获取节点
  if (!props.checkStrictly && node.childNodes.length > 0) {
    treeToList(node).forEach((item) => {
      if (item.childNodes.length <= 0) {
        treeRef.value.setChecked(item, false)
      }
    });
  }
  popoverHide()
}

// 下拉框关闭执行
const emits = defineEmits(['getValue'])
const popoverHide = function () {
  emits('getValue', returnDataKeys.value, returnDatas.value)
}

// 树形转为集合
function treeToList(tree: any) {
  let queen: Array<any> = []
  const out: Array<any> = []
  queen = queen.concat(tree)
  while (queen.length) {
    const first = queen.shift()
    if (first.childNodes) {
      queen = queen.concat(first.childNodes)
    }
    out.push(first)
  }
  return out
}

// 过滤
function filterNode(value: any, data: any) {
  if (!value) return true
  return data.name.indexOf(value) !== -1
}

</script>

<style scoped>
.common-tree {
  overflow: auto;
}

.tree-select {
  z-index: 111;
}

.ok {
  float: right;
}

.el-row {
  padding-top: 0px !important;
}
</style>
